package com.yinuo.face;

import android.graphics.Rect;

import com.arcsoft.facedetection.AFD_FSDKEngine;
import com.arcsoft.facedetection.AFD_FSDKError;
import com.arcsoft.facedetection.AFD_FSDKFace;
import com.arcsoft.facerecognition.AFR_FSDKEngine;
import com.arcsoft.facerecognition.AFR_FSDKError;
import com.arcsoft.facerecognition.AFR_FSDKFace;
import com.arcsoft.facerecognition.AFR_FSDKMatching;
import com.arcsoft.facetracking.AFT_FSDKEngine;
import com.arcsoft.facetracking.AFT_FSDKError;
import com.arcsoft.facetracking.AFT_FSDKFace;
import com.google.common.base.Stopwatch;
import com.orhanobut.logger.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by panmingzhi on 2018/10/4.
 */

public class ArcSdkEngine {

    public static final String APPID = "pdhEENp6Ph69tmrMaF6tUPQcT5vQJV1Wu59aNaUmHmn";
    public static final String FTSDKKEY = "ATVGfqbcLuXSzRXcrhmnE1N3oNNFfY9QTnCr3XJqW1Cd";
    public static final String FDSDKKEY = "ATVGfqbcLuXSzRXcrhmnE1NAxmdMb1zASdV8qX7j8bGz";
    public static final String FRSDKKEY = "ATVGfqbcLuXSzRXcrhmnE1NfcNg6u1yrL5bZhPVd3ctx";
    int[] focArr = {AFR_FSDKEngine.AFR_FOC_0, AFR_FSDKEngine.AFR_FOC_270, AFR_FSDKEngine.AFR_FOC_180, AFR_FSDKEngine.AFR_FOC_90};
    private Map<String, AFR_FSDKFace> faceMapCache = new HashMap<>();
    private AFT_FSDKEngine aft_fsdkEngine;
    private AFD_FSDKEngine afd_fsdkEngine;
    private AFR_FSDKEngine afr_fsdkEngine;
    private List<AFT_FSDKFace> aft_fsdkFaces = new ArrayList<>();
    private List<AFD_FSDKFace> afd_fsdkFaces = new ArrayList<>();
    private AFR_FSDKMatching score = new AFR_FSDKMatching();

    private ArcSdkEngine() {

    }

    public static ArcSdkEngine getInstance() {
        return ArcSdkEngineHolder.instance;
    }

    public void init() {
        Logger.i("APPID:%s",APPID);
        Logger.i("FTSDKKEY:%s",FTSDKKEY);
        Logger.i("FDSDKKEY:%s",FDSDKKEY);
        Logger.i("FRSDKKEY:%s",FRSDKKEY);

        aft_fsdkEngine = new AFT_FSDKEngine();
        AFT_FSDKError aft_fsdkError = aft_fsdkEngine.AFT_FSDK_InitialFaceEngine(APPID, FTSDKKEY, AFT_FSDKEngine.AFT_OPF_0_HIGHER_EXT, 16, 5);
        Logger.i("aft_fsdk:%d",aft_fsdkError.getCode());

        afd_fsdkEngine = new AFD_FSDKEngine();
        AFD_FSDKError afd_fsdkError = afd_fsdkEngine.AFD_FSDK_InitialFaceEngine(APPID, FDSDKKEY, AFD_FSDKEngine.AFD_OPF_0_HIGHER_EXT, 16, 5);
        Logger.i("afd_fsdk:%d",afd_fsdkError.getCode());

        afr_fsdkEngine = new AFR_FSDKEngine();
        AFR_FSDKError afr_fsdkError = afr_fsdkEngine.AFR_FSDK_InitialEngine(APPID, FRSDKKEY);
        Logger.i("afr_fsdk:%d",afr_fsdkError.getCode());
    }

    public void unInit() {
        if (aft_fsdkEngine != null) {
            aft_fsdkEngine.AFT_FSDK_UninitialFaceEngine();
        }
        if (afd_fsdkEngine != null) {
            afd_fsdkEngine.AFD_FSDK_UninitialFaceEngine();
        }
        if (afr_fsdkEngine != null) {
            afr_fsdkEngine.AFR_FSDK_UninitialEngine();
        }
    }

    public void track(byte[] data, int width, int height, List<Rect> list) {
        Stopwatch started = Stopwatch.createStarted();
        list.clear();
        aft_fsdkFaces.clear();
        AFT_FSDKError aft_fsdkError = aft_fsdkEngine.AFT_FSDK_FaceFeatureDetect(data, width, height, AFT_FSDKEngine.CP_PAF_NV21, aft_fsdkFaces);
        if (aft_fsdkError.getCode() == 0 && !aft_fsdkFaces.isEmpty()) {
            for (AFT_FSDKFace aft_fsdkFace : aft_fsdkFaces) {
                list.add(aft_fsdkFace.getRect());
            }
        }
        Logger.d("人脸追踪耗时:%d", started.elapsed(TimeUnit.MILLISECONDS));
    }

    public void detection(byte[] data, int width, int height, List<Rect> list) {
        Stopwatch started = Stopwatch.createStarted();
        afd_fsdkFaces.clear();
        list.clear();
        AFD_FSDKError afd_fsdkError = afd_fsdkEngine.AFD_FSDK_StillImageFaceDetection(data, width, height, AFD_FSDKEngine.CP_PAF_NV21, afd_fsdkFaces);
        if (afd_fsdkError.getCode() == 0 && !afd_fsdkFaces.isEmpty()) {
            for (AFD_FSDKFace afd_fsdkFace : afd_fsdkFaces) {
                list.add(afd_fsdkFace.getRect());
            }
        }
        Logger.d("人脸检测耗时:%d", started.elapsed(TimeUnit.MILLISECONDS));
    }

    public AFR_FSDKFace feature(byte[] data, int width, int height, Rect rect, int rotation) {
        Stopwatch started = Stopwatch.createStarted();
        try {
            AFR_FSDKFace feature = new AFR_FSDKFace();
            AFR_FSDKError afr_fsdkError = afr_fsdkEngine.AFR_FSDK_ExtractFRFeature(data, width, height, AFR_FSDKEngine.CP_PAF_NV21, rect, focArr[rotation / 90], feature);
            if (afr_fsdkError.getCode() == 0) {
                return feature;
            }
            return null;
        } catch (Exception e) {
            Logger.e(e, "抽取人脸特征失败");
            return null;
        } finally {
            Logger.d("抽取人脸特征耗时:%d", started.elapsed(TimeUnit.MILLISECONDS));
        }
    }

    public void addToCache(String userId, AFR_FSDKFace data) {
        faceMapCache.put(userId, data);
    }

    public void removeToCache(String userId) {
        faceMapCache.remove(userId);
    }

    public String valid(AFR_FSDKFace data1) {
        Set<Map.Entry<String, AFR_FSDKFace>> entries = faceMapCache.entrySet();
        for (Map.Entry<String, AFR_FSDKFace> entry : entries) {
            AFR_FSDKError afr_fsdkError = afr_fsdkEngine.AFR_FSDK_FacePairMatching(data1, entry.getValue(), score);
            if (afr_fsdkError.getCode() != 0) {
                return null;
            }

            if (score.getScore() > 0.65) {
                return entry.getKey();
            }
        }

        return null;
    }

    public void cleanCache() {
        faceMapCache.clear();
    }

    private static class ArcSdkEngineHolder {
        public static ArcSdkEngine instance = new ArcSdkEngine();
    }

}
